#![allow(unused)]

use tweeny_rpc::utils::helper_types::*;

/*
trait CoolServ {
    async fn proc1(&self, name: &'static str, number: usize) -> (DeserRefSrcBoxedBytes, &'static str);
    async fn proc2(
        &self,
        x: usize,
        b: (&'static [u8], DeserRefSrcArcBytes),
    ) -> Result<(f64, &'static str), ()>;
    async fn proc3(&self, a: [u8; 10]);
}
*/

// generated, common:
use ::tweeny_rpc::utils::{
    maybe_deser_owned::{
        derive_macro::VariantMaybeDeserOwned, MaybeDeserOwned, VariantMaybeDeserOwned,
    },
    serde::{Deserialize, Serialize},
};
#[derive(Serialize, Deserialize, VariantMaybeDeserOwned)]
enum CoolServReq {
    Call1(&'static str, usize),
    Call2(usize, (&'static [u8], DeserRefSrcArcBytes)),
    Call3([u8; 10]),
}
#[derive(Serialize, Deserialize, VariantMaybeDeserOwned)]
#[serde(bound(deserialize = "'de: 'static"))]
enum CoolServResp {
    Call1((DeserRefSrcBoxedBytes, &'static str)),
    Call2(Result<(f64, &'static str), ()>),
    Call3(()),
}

// generated, server only:
use ::std::future::Future;
use ::tweeny_rpc::server::ServeRpc;
trait CoolServ {
    type OtherEndInfo: Send;
    fn proc1(
        &self,
        from: Self::OtherEndInfo,
        name: &'static str,
        number: usize,
    ) -> impl Future<Output = (DeserRefSrcBoxedBytes, &'static str)> + Send;

    fn proc2(
        &self,
        from: Self::OtherEndInfo,
        x: usize,
        b: (&'static [u8], DeserRefSrcArcBytes),
    ) -> impl Future<Output = Result<(f64, &'static str), ()>> + Send;
    fn proc3(&self, from: Self::OtherEndInfo, a: [u8; 10]) -> impl Future<Output = ()> + Send;
}
struct CoolServServerWrapper<T>(T);
impl<T: CoolServ + Sync + Send + 'static> ServeRpc for CoolServServerWrapper<T> {
    type OtherEndInfo = T::OtherEndInfo;
    type Req = CoolServReq;
    type Resp = CoolServResp;

    fn dispatch_call(
        &self,
        req: Self::Req,
        from: Self::OtherEndInfo,
    ) -> impl Future<Output = Self::Resp> + Send {
        async move {
            match req {
                CoolServReq::Call1(name, number) => {
                    CoolServResp::Call1(self.0.proc1(from, name, number).await)
                }
                CoolServReq::Call2(x, b) => CoolServResp::Call2(self.0.proc2(from, x, b).await),
                CoolServReq::Call3(a) => CoolServResp::Call3(self.0.proc3(from, a).await),
            }
        }
    }
}

// generated, client only:
use ::std::time::Duration;
use ::tweeny_rpc::{
    client::{error::CallError, RequestHandle},
    courier::codec::{FromSliceDeserializer, ToWriterSerializer},
    utils::OwnedOrRefWithSrc,
};
#[derive(Clone)]
struct CoolServReqHandle<Ser, Deser>(RequestHandle<CoolServReq, CoolServResp, Ser, Deser>)
where
    Ser: ToWriterSerializer,
    Deser: FromSliceDeserializer;
impl<Ser: ToWriterSerializer, Deser: FromSliceDeserializer> CoolServReqHandle<Ser, Deser> {
    async fn proc1(
        &self,
        name: &'static str,
        number: usize,
        timeout: Option<Duration>,
    ) -> Result<
        OwnedOrRefWithSrc<(DeserRefSrcBoxedBytes, &'static str)>,
        CallError<Ser::Err, Deser::Err>,
    > {
        let res = self
            .0
            .call(CoolServReq::Call1(name, number), timeout)
            .await?;
        unsafe {
            res.try_map_inner(|x| match x {
                CoolServResp::Call1(r) => Ok(r),
                _ => Err(CallError::RespMismatch),
            })
        }
    }
    async fn proc2(
        &self,
        x: usize,
        b: (&'static [u8], DeserRefSrcArcBytes),
        timeout: Option<Duration>,
    ) -> Result<OwnedOrRefWithSrc<Result<(f64, &'static str), ()>>, CallError<Ser::Err, Deser::Err>>
    {
        let res = self
            .0
            .call(CoolServReq::Call2(x, b), timeout)
            .await?;
        unsafe {
            res.try_map_inner(|x| match x {
                CoolServResp::Call2(r) => Ok(r),
                _ => Err(CallError::RespMismatch),
            })
        }
    }
    async fn proc3(
        &self,
        a: [u8; 10],
        timeout: Option<Duration>,
    ) -> Result<OwnedOrRefWithSrc<()>, CallError<Ser::Err, Deser::Err>> {
        let res = self
            .0
            .call(CoolServReq::Call3(a), timeout)
            .await?;
        unsafe {
            res.try_map_inner(|x| match x {
                CoolServResp::Call3(r) => Ok(r),
                _ => Err(CallError::RespMismatch),
            })
        }
    }
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    use std::net::SocketAddr;
    use std::{str::FromStr, sync::Arc};
    use tweeny_rpc::{client::with_default_serder_tcp, server::Server};

    struct CoolServer;
    impl CoolServ for CoolServer {
        type OtherEndInfo = SocketAddr;
        fn proc1(
            &self,
            from: Self::OtherEndInfo,
            name: &'static str,
            number: usize,
        ) -> impl Future<Output = (DeserRefSrcBoxedBytes, &'static str)> + Send {
            async move { todo!() }
        }
        fn proc2(
            &self,
            from: Self::OtherEndInfo,
            x: usize,
            b: (&'static [u8], DeserRefSrcArcBytes),
        ) -> impl Future<Output = Result<(f64, &'static str), ()>> + Send {
            async move { todo!() }
        }
        fn proc3(&self, from: Self::OtherEndInfo, a: [u8; 10]) -> impl Future<Output = ()> + Send {
            async move { todo!() }
        }
    }

    let addr = SocketAddr::from_str("127.0.0.1:22330").unwrap();
    let serv =
        Server::with_default_serder_tcp(Arc::new(CoolServServerWrapper(CoolServer)), addr).await?;
    tokio::spawn(serv.serve());

    let (client_serv, client_handle) = with_default_serder_tcp(addr).await?;
    tokio::spawn(client_serv);
    let client_handle = CoolServReqHandle(client_handle);
    let _ = client_handle.proc3([0u8; 10], None).await;
    Ok(())
}
